use image::{DynamicImage, RgbImage};

use crate::matrix::Vec3f;

pub struct Texture {
    img: RgbImage,
    width: f32,
    height: f32,
}
impl Texture {
    pub fn new(img: DynamicImage) -> Self {
        let img = img.as_rgb8().unwrap().to_owned();
        let (width, height) = img.dimensions();
        // println!("texture width{width},height{height}");
        Self {
            img,
            width: width as f32,
            height: height as f32,
        }
    }
    pub fn get_color(&self, u: f32, v: f32) -> Vec3f {
        let u = u.clamp(0.0f32, 1.0f32);
        let v = v.clamp(0.0f32, 1.0f32);
        let u_img = u * self.width;
        let v_img = (1.0 - v) * self.height;
        self.img
            .get_pixel(v_img as u32, u_img as u32)
            .0
            .map(|p| p as f32)
            .into()
    }
    pub fn get_color_bilinear(&self, u: f32, v: f32) -> Vec3f {
        let u = u.clamp(0.0f32, 1.0f32);
        let v = v.clamp(0.0f32, 1.0f32);
        let u_img = u * self.width;
        let v_img = (1.0 - v) * self.height;
        let u_max = u_img.ceil().min(self.width);
        let u_min = u_img.floor().max(0.);
        let v_max = v_img.ceil().min(self.height);
        let v_min = v_img.floor().max(0.);

        //Up Left Point
        let color_ul: Vec3f = self
            .img
            .get_pixel(v_max as u32, u_min as u32)
            .0
            .map(|c| c as f32)
            .into();
        //Up Right Point
        let color_ur: Vec3f = self
            .img
            .get_pixel(v_max as u32, u_max as u32)
            .0
            .map(|c| c as f32)
            .into();
        //Down Left Point
        let color_dl: Vec3f = self
            .img
            .get_pixel(v_min as u32, u_min as u32)
            .0
            .map(|c| c as f32)
            .into();
        //Down Right Point
        let color_dr: Vec3f = self
            .img
            .get_pixel(v_min as u32, u_max as u32)
            .0
            .map(|c| c as f32)
            .into();

        let u_lerp_num = (u_img - u_min) / (u_max - u_min);
        let v_lerp_num = (v_img - v_min) / (v_max - v_min);

        //U Up Lerp
        let color_up_u_lerp = color_ul * u_lerp_num + color_ur * (1. - u_lerp_num);
        //U Down Lerp
        let color_down_u_lerp = color_dl * u_lerp_num + color_dr * (1. - u_lerp_num);
        //V Lerp
        let color: Vec3f = color_down_u_lerp * v_lerp_num + color_up_u_lerp * (1. - v_lerp_num);

        Vec3f::from(color)
    }
}
